package com.cencat.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cencat.order.entity.OrderInfo;
import com.cencat.order.entity.OrderItem;
import com.cencat.order.mapper.OrderInfoMapper;
import com.cencat.order.service.OrderInfoService;
import com.cencat.order.service.OrderItemService;
import com.cencat.order.dto.OrderCreateDTO;
import com.cencat.order.dto.OrderQueryDTO;
import com.cencat.order.dto.OrderUpdateDTO;
import com.cencat.order.vo.OrderDetailVO;
import com.cencat.order.vo.OrderStatisticsVO;
import com.cencat.order.vo.OrderVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 订单信息服务实现类
 * 
 * @author cencat
 * @since 2024-01-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    private final OrderItemService orderItemService;
    private static final AtomicLong ORDER_SEQUENCE = new AtomicLong(1);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDetailVO createOrder(OrderCreateDTO orderCreateDTO) {
        log.info("开始创建订单，用户ID：{}", orderCreateDTO.getUserId());
        
        // 1. 创建订单基本信息
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderCreateDTO, orderInfo);
        orderInfo.setOrderNo(generateOrderNo());
        orderInfo.setOrderStatus(0); // 待支付
        orderInfo.setPaymentStatus(0); // 未支付
        orderInfo.setShippingStatus(0); // 未发货
        orderInfo.setCreateTime(LocalDateTime.now());
        orderInfo.setUpdateTime(LocalDateTime.now());
        
        // 2. 计算订单总金额
        BigDecimal totalAmount = orderCreateDTO.getOrderItems().stream()
                .map(item -> item.getUnitPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        orderInfo.setTotalAmount(totalAmount);
        orderInfo.setPayableAmount(totalAmount.subtract(orderCreateDTO.getDiscountAmount() != null ? 
                orderCreateDTO.getDiscountAmount() : BigDecimal.ZERO));
        
        // 3. 保存订单
        boolean saved = save(orderInfo);
        if (!saved) {
            throw new RuntimeException("订单创建失败");
        }
        
        // 4. 创建订单明细
        orderItemService.batchCreateOrderItems(orderInfo.getId(), orderCreateDTO.getOrderItems());
        
        // 5. 预占库存
        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderInfo.getId())
                .stream().map(vo -> {
                    OrderItem item = new OrderItem();
                    BeanUtils.copyProperties(vo, item);
                    return item;
                }).collect(Collectors.toList());
        orderItemService.reserveInventory(orderItems);
        
        log.info("订单创建成功，订单号：{}", orderInfo.getOrderNo());
        return getOrderDetail(orderInfo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrder(Long orderId, OrderUpdateDTO orderUpdateDTO) {
        log.info("开始更新订单，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        // 检查订单状态是否允许修改
        if (orderInfo.getOrderStatus() > 1) {
            throw new RuntimeException("订单状态不允许修改");
        }
        
        BeanUtils.copyProperties(orderUpdateDTO, orderInfo);
        orderInfo.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(orderInfo);
        log.info("订单更新{}，订单ID：{}", updated ? "成功" : "失败", orderId);
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOrder(Long orderId, String cancelReason, Long operatorId) {
        log.info("开始取消订单，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        // 检查订单状态
        if (!validateStatusChange(orderInfo.getOrderStatus(), 5)) {
            throw new RuntimeException("订单状态不允许取消");
        }
        
        // 更新订单状态
        int result = baseMapper.cancelOrder(orderId, cancelReason, operatorId.toString());
        
        if (result > 0) {
            // 释放库存
            List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderId)
                    .stream().map(vo -> {
                        OrderItem item = new OrderItem();
                        BeanUtils.copyProperties(vo, item);
                        return item;
                    }).collect(Collectors.toList());
            orderItemService.releaseInventory(orderItems);
            
            log.info("订单取消成功，订单ID：{}", orderId);
            return true;
        }
        
        log.warn("订单取消失败，订单ID：{}", orderId);
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmOrder(Long orderId, Long operatorId) {
        log.info("开始确认订单，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        if (!validateStatusChange(orderInfo.getOrderStatus(), 1)) {
            throw new RuntimeException("订单状态不允许确认");
        }
        
        orderInfo.setOrderStatus(1); // 已确认
        orderInfo.setUpdateBy(operatorId.toString());
        orderInfo.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(orderInfo);
        log.info("订单确认{}，订单ID：{}", updated ? "成功" : "失败", orderId);
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean shipOrder(Long orderId, String logisticsCompany, String logisticsNo, Long operatorId) {
        log.info("开始发货，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        if (!validateStatusChange(orderInfo.getOrderStatus(), 2)) {
            throw new RuntimeException("订单状态不允许发货");
        }
        
        int result = baseMapper.updateShippingInfo(orderId, 1, logisticsCompany, 
                logisticsNo, operatorId.toString());
        
        if (result > 0) {
            // 扣减库存
            List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderId)
                    .stream().map(vo -> {
                        OrderItem item = new OrderItem();
                        BeanUtils.copyProperties(vo, item);
                        return item;
                    }).collect(Collectors.toList());
            orderItemService.deductInventory(orderItems);
            
            // 更新订单状态
            orderInfo.setOrderStatus(2); // 已发货
            orderInfo.setUpdateBy(operatorId.toString());
            orderInfo.setUpdateTime(LocalDateTime.now());
            updateById(orderInfo);
            
            log.info("订单发货成功，订单ID：{}", orderId);
            return true;
        }
        
        log.warn("订单发货失败，订单ID：{}", orderId);
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean completeOrder(Long orderId, Long operatorId) {
        log.info("开始完成订单，订单ID：{}", orderId);
        
        int result = baseMapper.completeOrder(orderId, operatorId.toString());
        
        boolean success = result > 0;
        log.info("订单完成{}，订单ID：{}", success ? "成功" : "失败", orderId);
        return success;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean payOrder(Long orderId, String paymentMethod, BigDecimal paidAmount, 
                           String transactionNo, Long operatorId) {
        log.info("开始支付订单，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        if (orderInfo.getPaymentStatus() != 0) {
            throw new RuntimeException("订单已支付或支付状态异常");
        }
        
        int result = baseMapper.updatePaymentStatus(orderId, 1, paymentMethod, 
                paidAmount, operatorId.toString());
        
        if (result > 0) {
            // 更新订单状态为已支付
            orderInfo.setOrderStatus(1);
            orderInfo.setTransactionNo(transactionNo);
            orderInfo.setUpdateBy(operatorId.toString());
            orderInfo.setUpdateTime(LocalDateTime.now());
            updateById(orderInfo);
            
            log.info("订单支付成功，订单ID：{}", orderId);
            return true;
        }
        
        log.warn("订单支付失败，订单ID：{}", orderId);
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refundOrder(Long orderId, BigDecimal refundAmount, String refundReason, Long operatorId) {
        log.info("开始退款，订单ID：{}", orderId);
        
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            throw new RuntimeException("订单不存在");
        }
        
        if (orderInfo.getPaymentStatus() != 1) {
            throw new RuntimeException("订单未支付，无法退款");
        }
        
        // 更新支付状态为已退款
        int result = baseMapper.updatePaymentStatus(orderId, 2, null, refundAmount.negate(), 
                operatorId.toString());
        
        if (result > 0) {
            // 更新订单状态
            orderInfo.setOrderStatus(6); // 已退款
            orderInfo.setRefundReason(refundReason);
            orderInfo.setRefundTime(LocalDateTime.now());
            orderInfo.setUpdateBy(operatorId.toString());
            orderInfo.setUpdateTime(LocalDateTime.now());
            updateById(orderInfo);
            
            // 恢复库存
            List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderId)
                    .stream().map(vo -> {
                        OrderItem item = new OrderItem();
                        BeanUtils.copyProperties(vo, item);
                        return item;
                    }).collect(Collectors.toList());
            orderItemService.restoreInventory(orderItems);
            
            log.info("订单退款成功，订单ID：{}", orderId);
            return true;
        }
        
        log.warn("订单退款失败，订单ID：{}", orderId);
        return false;
    }

    @Override
    public IPage<OrderVO> pageOrders(Page<OrderInfo> page, OrderQueryDTO queryDTO) {
        IPage<OrderInfo> orderPage = baseMapper.selectOrderPage(page,
                queryDTO.getUserId(),
                queryDTO.getMerchantId(),
                queryDTO.getOrderStatus(),
                queryDTO.getPaymentStatus(),
                queryDTO.getStartTime(),
                queryDTO.getEndTime());
        
        return orderPage.convert(this::convertToOrderVO);
    }

    @Override
    public OrderDetailVO getOrderByOrderNo(String orderNo) {
        OrderInfo orderInfo = baseMapper.selectByOrderNo(orderNo);
        if (orderInfo == null) {
            return null;
        }
        return getOrderDetail(orderInfo.getId());
    }

    @Override
    public OrderDetailVO getOrderDetail(Long orderId) {
        OrderInfo orderInfo = getById(orderId);
        if (orderInfo == null) {
            return null;
        }
        
        OrderDetailVO orderDetailVO = new OrderDetailVO();
        BeanUtils.copyProperties(orderInfo, orderDetailVO);
        
        // 查询订单明细
        orderDetailVO.setOrderItems(orderItemService.getOrderItemsByOrderId(orderId));
        
        return orderDetailVO;
    }

    @Override
    public IPage<OrderVO> getUserOrders(Long userId, Integer orderStatus, Page<OrderInfo> page) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getUserId, userId)
                .eq(orderStatus != null, OrderInfo::getOrderStatus, orderStatus)
                .eq(OrderInfo::getDeleted, 0)
                .orderByDesc(OrderInfo::getCreateTime);
        
        IPage<OrderInfo> orderPage = page(page, wrapper);
        return orderPage.convert(this::convertToOrderVO);
    }

    @Override
    public IPage<OrderVO> getMerchantOrders(Long merchantId, Integer orderStatus, Page<OrderInfo> page) {
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getMerchantId, merchantId)
                .eq(orderStatus != null, OrderInfo::getOrderStatus, orderStatus)
                .eq(OrderInfo::getDeleted, 0)
                .orderByDesc(OrderInfo::getCreateTime);
        
        IPage<OrderInfo> orderPage = page(page, wrapper);
        return orderPage.convert(this::convertToOrderVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchUpdateOrderStatus(List<Long> orderIds, Integer orderStatus, Long operatorId) {
        int result = baseMapper.batchUpdateOrderStatus(orderIds, orderStatus, operatorId.toString());
        return result > 0;
    }

    @Override
    public List<OrderVO> getPendingOrders(Long merchantId) {
        List<OrderInfo> orderInfos = baseMapper.selectPendingOrders(merchantId);
        return orderInfos.stream().map(this::convertToOrderVO).collect(Collectors.toList());
    }

    @Override
    public List<OrderVO> getCompletedOrders(Long userId, Long merchantId, Integer limit) {
        List<OrderInfo> orderInfos = baseMapper.selectCompletedOrders(userId, merchantId, limit);
        return orderInfos.stream().map(this::convertToOrderVO).collect(Collectors.toList());
    }

    @Override
    public OrderStatisticsVO getOrderStatistics(Long userId, Long merchantId, 
                                               LocalDateTime startTime, LocalDateTime endTime) {
        OrderStatisticsVO statistics = new OrderStatisticsVO();
        
        // 统计订单数量
        List<Map<String, Object>> statusCounts = baseMapper.countByStatus(userId, merchantId, startTime, endTime);
        Map<Integer, Long> statusCountMap = statusCounts.stream()
                .collect(Collectors.toMap(
                        map -> (Integer) map.get("order_status"),
                        map -> ((Number) map.get("count")).longValue()
                ));
        
        statistics.setPendingCount(statusCountMap.getOrDefault(0, 0L));
        statistics.setConfirmedCount(statusCountMap.getOrDefault(1, 0L));
        statistics.setShippedCount(statusCountMap.getOrDefault(2, 0L));
        statistics.setDeliveredCount(statusCountMap.getOrDefault(3, 0L));
        statistics.setCompletedCount(statusCountMap.getOrDefault(4, 0L));
        statistics.setCancelledCount(statusCountMap.getOrDefault(5, 0L));
        statistics.setRefundedCount(statusCountMap.getOrDefault(6, 0L));
        
        // 计算总金额
        statistics.setTotalAmount(baseMapper.sumTotalAmount(userId, merchantId, null, startTime, endTime));
        statistics.setPaidAmount(baseMapper.sumTotalAmount(userId, merchantId, 1, startTime, endTime));
        
        return statistics;
    }

    @Override
    public BigDecimal calculateTotalAmount(Long userId, Long merchantId, Integer orderStatus,
                                          LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.sumTotalAmount(userId, merchantId, orderStatus, startTime, endTime);
    }

    @Override
    public String generateOrderNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String sequence = String.format("%06d", ORDER_SEQUENCE.getAndIncrement() % 1000000);
        return "ORD" + timestamp + sequence;
    }

    @Override
    public boolean validateStatusChange(Integer currentStatus, Integer targetStatus) {
        // 订单状态流转规则
        Map<Integer, Set<Integer>> statusFlowMap = new HashMap<>();
        statusFlowMap.put(0, Set.of(1, 5)); // 待支付 -> 已确认/已取消
        statusFlowMap.put(1, Set.of(2, 5)); // 已确认 -> 已发货/已取消
        statusFlowMap.put(2, Set.of(3, 5)); // 已发货 -> 已送达/已取消
        statusFlowMap.put(3, Set.of(4));    // 已送达 -> 已完成
        statusFlowMap.put(4, Set.of(6));    // 已完成 -> 已退款
        
        return statusFlowMap.getOrDefault(currentStatus, Collections.emptySet()).contains(targetStatus);
    }

    @Override
    public boolean checkOrderBelongsToUser(Long orderId, Long userId) {
        OrderInfo orderInfo = getById(orderId);
        return orderInfo != null && Objects.equals(orderInfo.getUserId(), userId);
    }

    @Override
    public boolean checkOrderBelongsToMerchant(Long orderId, Long merchantId) {
        OrderInfo orderInfo = getById(orderId);
        return orderInfo != null && Objects.equals(orderInfo.getMerchantId(), merchantId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int autoCancelTimeoutOrders(int timeoutMinutes) {
        LocalDateTime timeoutTime = LocalDateTime.now().minusMinutes(timeoutMinutes);
        
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderStatus, 0) // 待支付
                .eq(OrderInfo::getPaymentStatus, 0) // 未支付
                .lt(OrderInfo::getCreateTime, timeoutTime)
                .eq(OrderInfo::getDeleted, 0);
        
        List<OrderInfo> timeoutOrders = list(wrapper);
        
        int cancelledCount = 0;
        for (OrderInfo order : timeoutOrders) {
            if (cancelOrder(order.getId(), "系统自动取消：超时未支付", 0L)) {
                cancelledCount++;
            }
        }
        
        log.info("自动取消超时订单完成，取消数量：{}", cancelledCount);
        return cancelledCount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int autoConfirmTimeoutOrders(int timeoutDays) {
        LocalDateTime timeoutTime = LocalDateTime.now().minusDays(timeoutDays);
        
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderStatus, 3) // 已送达
                .lt(OrderInfo::getDeliveryTime, timeoutTime)
                .eq(OrderInfo::getDeleted, 0);
        
        List<OrderInfo> timeoutOrders = list(wrapper);
        
        int confirmedCount = 0;
        for (OrderInfo order : timeoutOrders) {
            if (completeOrder(order.getId(), 0L)) {
                confirmedCount++;
            }
        }
        
        log.info("自动确认收货完成，确认数量：{}", confirmedCount);
        return confirmedCount;
    }

    /**
     * 转换为OrderVO
     */
    private OrderVO convertToOrderVO(OrderInfo orderInfo) {
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orderInfo, orderVO);
        return orderVO;
    }
}